import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;

import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.datatypes.TypeMapper;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;
import com.hp.hpl.jena.vocabulary.RDFS;

public class read {
	private static String sourcePath = "AT.tab";
	private static String writePath = "AT.csv";
	private static String rdfOutput = "Graph.rdf";
	private static Charset ENCODING = StandardCharsets.UTF_8;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		City c = getQueryResults("4060").get(0);
		queryEndpoint(c.getLongitude(), c.getLatitude(), 0.01);
	}
	
	static void queryEndpoint(String longitude, String latitude, double distance){
		String sparqlEndpointUrl = "http://linkedgeodata.org/vsparql";

		Query query = QueryFactory.create(getEndpointQuery(longitude, latitude, distance));
//		Query query = QueryFactory.create("Prefix bif:<http://example.org/function#> Select * From <http://linkedgeodata.org> { ?s ?p ?o . FILTER(bif:st_intersects(?o, bif:st_point (4.892222, 52.373056), 5)) . Filter(Regex(?s, 'test', 'i')) . }");
    

		QueryExecution qexec = QueryExecutionFactory.sparqlService(sparqlEndpointUrl, query) ;
		Object row;
		try {
			ResultSet results =  qexec.execSelect() ;
//			ResultSetFormatter.out(System.out, results) ;
			while (results.hasNext()){
				row = results.nextSolution();
//				RDFNode thing= row.get("x");
//				Literal label= row.getLiteral("label");
			}
			
		}finally { qexec.close() ; }
		
	}
	
	static String getEndpointQuery(String longitude, String latitude, double distance){
		String s = "Prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
				+ "Prefix ogc: <http://www.opengis.net/ont/geosparql#>\n"
				+ "Prefix geom: <http://geovocab.org/geometry#>\n"
				+ "Prefix lgdo: <http://linkedgeodata.org/ontology/>\n"
				+ "Prefix bif: <http://www.openlinksw.com/schemas/bif#>\n"
				+ "Select * From <http://linkedgeodata.org> {\n"
				+ "?s a lgdo:Amenity ; \n"
				+ "rdfs:label ?l ;\n"
				+ "geom:geometry [\n"
				+ "ogc:asWKT ?g\n"
				+ "] .\n"
				+ "Filter(bif:st_intersects (?g, bif:st_point (" + longitude + ", " + latitude + "), " + distance +")) .\n"
				+ "}";
//		System.out.println(s);
		return s;
	}
	
	static ArrayList<City> getQueryResults(String zip){
		Model model = RDFDataMgr.loadModel(rdfOutput);
		String nsX = "http://www.example.com/x.rdf#";
		String nsAustria = "http://www.example.com/austria/";
		Query query = QueryFactory.create(getQuery(zip));
		QueryExecution qexec = QueryExecutionFactory.create(query, model);
		
		Property hasName = model.createProperty(nsX + "hasName");
		ArrayList<City> resultList = new ArrayList<City>();
		City c; 
		try {
			ResultSet results = qexec.execSelect();
			while (results.hasNext()) {
				QuerySolution soln = results.nextSolution();
				Resource s = soln.getResource("place");
				RDFNode zipLiteral = soln.getLiteral("?zip");
				RDFNode longLiteral = soln.getLiteral("long");
				RDFNode latLiteral = soln.getLiteral("lat");
				System.out.println("ID: " + s.toString().replace(nsAustria, "") + " " + s.getProperty(hasName).getString() + " " + zipLiteral.toString() + " Long:" + longLiteral.asLiteral().getDouble() + " Lat:" + latLiteral.asLiteral().getDouble());
				c = new City(s.toString().replace(nsAustria, ""), s.getProperty(hasName).getString(), Double.toString(latLiteral.asLiteral().getDouble()), Double.toString(longLiteral.asLiteral().getDouble()));
				c.addZipCode(Integer.parseInt(zipLiteral.toString()));
				resultList.add(c);
			}
		} finally {
			qexec.close();
		}
		return resultList;
	}
	
	static String getQuery(String zipCode){
		String s = "PREFIX austria: <http://www.example.com/austria>\n";
		s = s + "PREFIX x: <http://www.example.com/x.rdf#>\n"
				+ "SELECT ?place ?name ?long ?lat ?zip\n"
				+ "WHERE {\n"
				+ "?place a <http://www.example.com/austria/place>.\n"
				+ "?place x:hasName ?name.\n"
				+ "?place x:hasLongitude ?long.\n"
				+ "?place x:hasZip ?zip.\n"
				+ "?place x:hasLatitude ?lat.\n"
				+ "FILTER (?zip=\""+ zipCode +"\")\n"
				+ "}";
		return s;
	}

	static Model createAndSave() {
		OntModel model = ModelFactory.createOntologyModel();

		String nsX = "http://www.example.com/x.rdf#";
		String nsAustria = "http://www.example.com/austria/";

		//
		model.setNsPrefix("x", nsX);
		model.setNsPrefix("austria", nsAustria);
		model.setNsPrefix("rdfs", RDFS.getURI());
		OntClass cityClass = model.createClass(nsAustria + "place");
		
		Property hasLongitude = model.createProperty(nsX + "hasLongitude");
		Property hasLatitude = model.createProperty(nsX + "hasLatitude");
		Property hasName = model.createProperty(nsX + "hasName");
		Property hasAsciiName = model.createProperty(nsX + "hasAsciiName");
		Property hasZip = model.createProperty(nsX + "hasZip");
		// RDFDatatype longitudeType = m.ge
		
		Resource cityRes, asciiName;
		
		int i = 0;
		ArrayList<City> list = getCities();
		for (City city : list) {
			cityRes = cityClass.createIndividual(nsAustria + city.getLocationID());
//			cityRes = m.createResource(nsAustria + city.getLocationID());
			asciiName = model.createResource(nsAustria + city.getAsciiName());
			cityRes.addProperty(hasAsciiName, asciiName);
			cityRes.addLiteral(hasLongitude,
					Double.parseDouble(city.getLongitude()));
			cityRes.addLiteral(hasLatitude,
					Double.parseDouble(city.getLatitude()));
			
			for (int zip : city.getZipCodes()) {
				cityRes.addProperty(hasZip, Integer.toString(zip));
			}

			model.add(cityRes, hasName, city.getName());

			i++;
			if (i > 110000)
				break;
		}

		File file = new File(rdfOutput);

		try {
			// if file doesnt exists, then create it
			if (!file.exists()) {

				file.createNewFile();
			}
			FileWriter fw = new FileWriter(file.getAbsoluteFile());
			BufferedWriter bw = new BufferedWriter(fw);
			RDFDataMgr.write(bw, model, Lang.RDFXML);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return model;
	}

	static ArrayList<City> getCities() {
		ArrayList<City> list = new ArrayList<City>();
		int i = 0;
		try {
			String[] elems;
			List<String> res = new ArrayList<String>();
			for (String line : readSmallTextFile(sourcePath)) {
				elems = line.split("\t");
				if (elems[7].length() > 0 && elems[12].equals("Gemeinde")
						|| res.size() == 0) {
					res.add(elems[2] + ";" + elems[3] + ";" + elems[4] + ";"
							+ elems[5] + ";" + elems[7]);
					if (i > 0) {
						list.add(new City(elems[0], elems[2], elems[3],
								elems[4], elems[5]));
						for (String h : elems[7].split(",")) {
							list.get(i - 1).addZipCode(Integer.parseInt(h));
						}
					}

					i++;
				}
			}

			writeSmallTextFile(res, writePath);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return list;
	}

	static void writeSmallTextFile(List<String> aLines, String aFileName)
			throws IOException {
		Path path = Paths.get(aFileName);
		Files.write(path, aLines, ENCODING);
	}

	static List<String> readSmallTextFile(String aFileName) throws IOException {
		Path path = Paths.get(aFileName);
		return Files.readAllLines(path, ENCODING);
	}
}
